package croppingplanap;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;


import javax.swing.BorderFactory;
import javax.swing.JPanel;

public class RectSquarePanel extends JPanel implements MouseListener, MouseMotionListener{

	public static final int DEFAULT_WIDTH_OF_SQUARES = 6;
	public static final int DEFAULT_HEIGHT_OF_SQUARES = 6;
	
	public static final int DEFAULT_VGAP = 1;
	public static final int DEFAULT_HGAP = 1;
	
	private int widthOfSquares;
	private int heightOfSquares;
	
	private int squaresWide;
	private int squaresHigh;
	
	private int vgap;
	private int hgap;
	
	private int width;
	private int height;
	
	static final Color GRID_COLOR = Color.white;
	static final Color BORDER_COLOR = Color.black;
	
	static final Color EMPTY_COLOR = Color.white;  
	
	private Image offscreen;
	private Graphics dbg;
	private boolean ready = false;
	
	private Point firstSelected;
	private Point lastSelected;
	Crop nextConversion;
	Crop currentCrop;
	
	private CroppingPlan plan;
	private LegendPanel legend;
	
	public RectSquarePanel(int widthOfSquares, int heightOfSquares, int hgap, int vgap, CroppingPlan plan, LegendPanel legend){
		this.widthOfSquares = widthOfSquares;
		this.heightOfSquares = heightOfSquares;
		this.squaresWide = plan.getWidth();
		this.squaresHigh = plan.getHeight();
		this.hgap = hgap;
		this.vgap = vgap;
		this.width = hgap + (widthOfSquares + hgap) * squaresWide;
		this.height = vgap + (heightOfSquares + vgap) * squaresHigh;

		this.firstSelected = null;
		this.lastSelected = null;
		currentCrop = plan.getCrops().values().iterator().next();
		nextConversion = Crop.NOTHING;
		
		
		Dimension preferredSize = new Dimension(width, height);
		this.setMinimumSize(preferredSize);
		this.setPreferredSize(preferredSize);
		//System.out.println(preferredSize);
		
		ready = false;
		
		offscreen = null;
		
		this.plan = plan;
		this.legend = legend;
		
		setBackground(Color.white);
		
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
	}
	
	public RectSquarePanel(int widthOfSquares, int heightOfSquares, int hgap, int vgap, CroppingPlan plan){
		this(DEFAULT_WIDTH_OF_SQUARES, DEFAULT_HEIGHT_OF_SQUARES, DEFAULT_HGAP, DEFAULT_VGAP, plan, null);
	}
	
	
	public RectSquarePanel(CroppingPlan plan, LegendPanel legend){
		this(DEFAULT_WIDTH_OF_SQUARES, DEFAULT_HEIGHT_OF_SQUARES, DEFAULT_HGAP, DEFAULT_VGAP, plan, legend);
	}
	
	public RectSquarePanel(CroppingPlan plan){
		this(DEFAULT_WIDTH_OF_SQUARES, DEFAULT_HEIGHT_OF_SQUARES, DEFAULT_HGAP, DEFAULT_VGAP, plan, null);
	}
	
	public void setReady(boolean ready){
		this.ready = ready;
	}

	public Point getSquare(Point p){
		return getSquare(p.x, p.y);
	}
	
	public Point getSquare(int x, int y){
//		if ((y - vgap) % (heightOfSquares + vgap) == 0) return null;
	//	else if ((x - hgap) % (widthOfSquares + hgap) == 0) return null;
		
		int resultY = (y - vgap) / (heightOfSquares + vgap);
		int resultX = (x - hgap) / (widthOfSquares + hgap);
		if(resultY < 0 || resultY >= squaresHigh) return null;
		else if(resultX < 0 || resultX >= squaresWide) return null;
		return new Point(resultX, resultY);
	}
	
	public void paint(Graphics g){
		if(ready){
			if(offscreen == null){
				offscreen = createImage(width, height);
				dbg = offscreen.getGraphics();
			}
			dbg.clearRect(0, 0, width, height);
			drawGrid(dbg);
			drawSquares(dbg);
			g.drawImage(offscreen, 0, 0, null);
		}
	}
	
	public void update(Graphics g){
		paint(g);
	}

	
	public void drawSquares(Graphics g){
		int selected;
		Point p = new Point();
		for(p.x = 0; p.x < squaresWide; p.x++){
			for(p.y = 0; p.y < squaresHigh; p.y++){
				selected = isSelected(p);
				if(selected == 0){
					g.setColor(getColor(p));
					g.fillRect(p.x * (widthOfSquares + hgap) + hgap, p.y * (heightOfSquares + vgap) + vgap, widthOfSquares, heightOfSquares);
				}else{
					Color c = getCurrentCropColor().brighter().brighter().brighter().brighter();
					
					g.setColor(c);
					if(selected == 1){
						
						g.fillRect(p.x * (widthOfSquares + hgap) + hgap, p.y * (heightOfSquares + vgap) + vgap, widthOfSquares, heightOfSquares);
						g.setColor(GRID_COLOR);
						g.drawLine(p.x * (widthOfSquares + hgap) + hgap, p.y * (heightOfSquares + vgap) + vgap, (p.x + 1) * (widthOfSquares + hgap), (p.y + 1) * (heightOfSquares + vgap));
						g.drawLine((p.x + 1) * (widthOfSquares + hgap), p.y * (heightOfSquares + vgap) + vgap,p.x * (widthOfSquares + hgap) + hgap, (p.y + 1) * (heightOfSquares + vgap));
					}else{
						g.fillRect(p.x * (widthOfSquares + hgap) + hgap, p.y * (heightOfSquares + vgap) + vgap, widthOfSquares, heightOfSquares);
					}
					g.setColor(BORDER_COLOR);
					g.drawRect(p.x * (widthOfSquares + hgap) + hgap, p.y * (heightOfSquares + vgap) + vgap, widthOfSquares - 1, heightOfSquares - 1);
				}
				
								
				/*
				
				if(firstSelected != null && lastSelected != null && withinBounds(p, firstSelected, lastSelected) && squareStates[p.x][p.y] != nextState){
					g.setColor(SELECTED_COLOR);
					g.fillRect(p.x * (widthOfSquares + hgap) + hgap, p.y * (heightOfSquares + vgap) + vgap, widthOfSquares, heightOfSquares);
					if(nextState == SquareState.off){
						g.setColor(GRID_COLOR);
						g.drawLine(p.x * (widthOfSquares + hgap) + hgap, p.y * (heightOfSquares + vgap) + vgap, (p.x + 1) * (widthOfSquares + hgap), (p.y + 1) * (heightOfSquares + vgap));
						g.drawLine((p.x + 1) * (widthOfSquares + hgap), p.y * (heightOfSquares + vgap) + vgap,p.x * (widthOfSquares + hgap) + hgap, (p.y + 1) * (heightOfSquares + vgap));
					}
				}else{
					g.setColor(squareStates[p.x][p.y].getColor());
					g.fillRect(p.x * (widthOfSquares + hgap) + hgap, p.y * (heightOfSquares + vgap) + vgap, widthOfSquares, heightOfSquares);
				}
				*/
				
			}
		}
	}
	
	public void drawGrid(Graphics g){
		g.setColor(GRID_COLOR);
		
		int x0;
		int y0;
		
		//g.drawLine(0, 0, 0, HEIGHT);
		for(int x = 0; x <= squaresWide; x++){
			x0 = x * (widthOfSquares + hgap);
			g.drawLine(x0, 0, x0, height);
		}

		for(int y = 0; y <= squaresHigh; y++){
			y0 = y * (heightOfSquares + vgap);
			g.drawLine(0, y0, width, y0);
			
		}	
	
	}
	
	public Crop setCurrentCrop(Crop nextCrop){
		if(nextCrop == null) throw new NullPointerException();
		Crop result = currentCrop;
		currentCrop = nextCrop;
		return result;
	}
	
	public boolean withinBounds(Point p, Point bound1, Point bound2){
		return p.x >= Math.min(bound1.x, bound2.x) && p.x <= Math.max(bound1.x, bound2.x) &&
				p.y >= Math.min(bound1.y, bound2.y) && p.y <= Math.max(bound1.y, bound2.y) &&
				plan.getCropAt(p) != null;
	}
	
	public int isSelected(Point p){
		

		
		if(firstSelected != null && lastSelected != null && withinBounds(p, firstSelected, lastSelected) && nextConversion != plan.getCropAt(p)){
			return nextConversion == Crop.NOTHING ? 1 : 2;
		}
		return 0;
	}
	
	public Color getColor(Point p){
		Crop crop = plan.getCropAt(p);
		return (crop == null) ? RectSquarePanel.EMPTY_COLOR : crop.getColor();
	}
	
	public Color getCurrentCropColor(){
		return currentCrop.getColor();
		
	}
	
	@Override
	public void mousePressed(MouseEvent arg0) {
		Point square = getSquare(arg0.getPoint());
		if(square != null){
			firstSelected = square;
			lastSelected = square;
			nextConversion = plan.getCropAt(square) == currentCrop ? Crop.NOTHING : currentCrop;
			repaint();
		}
	}
	
	@Override
	public void mouseReleased(MouseEvent arg0) {
		if(firstSelected != null && lastSelected != null){
			plan.setRect(firstSelected, lastSelected, nextConversion);
			legend.refreshLegend();
		}
		
		firstSelected = null;
		lastSelected = null;
		
		repaint();
		nextConversion = Crop.NOTHING;
		
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		/*if((arg0.getModifiers() & MouseEvent.BUTTON1_MASK) == 0){
			if(firstSelected != null && nextState != null){
				for(Point p : selected){
					squareStates[p.x][p.y] = nextState; 
				}
			}
			
			firstSelected = null;
			selected.clear();
			repaint();
			nextState = null;
		}*/
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {

	}

	@Override
	public void mouseDragged(MouseEvent arg0) {
		Point square = getSquare(arg0.getPoint());
		if(square != null && firstSelected != null){
			lastSelected = square;
			repaint();
		}
		
	}

	@Override
	public void mouseMoved(MouseEvent arg0) {
	}
	
}
